/************************************************************************
Copyright 2003, 2004, 2005, 2006, 2007, 2008 Grid Technology Research Center,
National Institute of Advanced Industrial Science and Technology.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
************************************************************************/

package jp.aist.gtrc.plus.scheduler.specific.sge.jaxb.schema;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import jp.aist.gtrc.plus.scheduler.specific.sge.jaxb.common.JAXBSGEServer;

import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.helpers.DefaultHandler;

public class SGEXMLTest {

	private static DocumentBuilderFactory factory = null;
	private static DocumentBuilder builder = null;
	private JAXBContext context;
	private Unmarshaller unmarshaller;
	private Marshaller marshaller;

	private static final String packageName = JAXBSGEServer.class.getPackage().getName();

	private String normalizeXML(String objName, String xml) {

		if (objName.equals("queue")) {
			if (xml.indexOf("QINSTANCE:") != -1) {
				/*
				 * Drop invalid '/' at tag tail
				 * <QINSTANCE:all.q/>
				 *  ...
				 * </QINSTANCE:all.q/>
				 */
				return xml.replaceAll("QINSTANCE:\\S+/>", "QINSTANCE>");
			}
		} else if (objName.equals("job")) {
			if (xml.indexOf("context list") != -1) {
				/*
				 * Replace ' ' to '_'
				 * <context list>
				 *   <VA_variable>rsvid</VA_variable>
				 *   <VA_value>R123</VA_value>
				 * </context list>
				 */
				return xml.replaceAll("context list", "context_list");
			}
		}

		return xml;

	}

	private static synchronized void init() throws ParserConfigurationException {

		if (factory == null) {
			factory = DocumentBuilderFactory.newInstance();
			factory.setValidating(true);
			factory.setAttribute(
				"http://java.sun.com/xml/jaxp/properties/schemaLanguage",
				"http://www.w3.org/2001/XMLSchema");
		}

		if (builder == null) {
			builder = factory.newDocumentBuilder();
			builder.setErrorHandler(new DefaultHandler());
		}

	}

	void run() throws Exception {


		Document document;
		String objName = "queue";
		File file = new File(objName + ".xml");

		BufferedReader in = null;
		StringBuffer bf = new StringBuffer();

		try {
			in = new BufferedReader(new InputStreamReader(
				new FileInputStream(file)));
			String line;
			String last = "</" + objName + ">";
			while ((line = in.readLine()) != null) {
				bf.append(line);
				if (line.startsWith(last))
					break;
			}
		} finally {
			if (in != null) {
				in.close();
			}
		}

		String xml = normalizeXML(objName, bf.toString());
		InputSource is = new InputSource(new StringReader(xml));
		document = builder.parse(is);

		NodeList roots = document.getChildNodes();
		int index = (roots.getLength() < 2) ? 0 : 1;
		Node objsNode = roots.item(index);
		if (objsNode.getNodeName().equals(objName + "_list") == false) {
			System.out.println("something wrong in " + file.getAbsolutePath());
			return;
		}
		checkNode(document, objsNode, objName);

		if (false) {
			// Output normalized XML to sample.xml if you want
			TransformerFactory tfactory = TransformerFactory.newInstance();
	        Transformer transformer = tfactory.newTransformer();
	        StringWriter writer = new StringWriter();
	        transformer.transform(new DOMSource(document), new StreamResult(writer));
	        FileWriter w = new FileWriter("sample.xml");
	        w.write(writer.toString());
	        w.flush();
	        w.close();
		}

		context = JAXBContext.newInstance(packageName);
		unmarshaller = context.createUnmarshaller();

		marshaller = context.createMarshaller();
		marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                Boolean.TRUE);
		marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, objName + ".xsd");

		JAXBElement<?> elem = (JAXBElement<?>)unmarshaller.unmarshal(new File("sample.xml"));
		if (elem != null) {
			marshaller.marshal(elem, System.out);
		}
	}

	static final boolean validStr(String str) {

		return ((str != null) && (str.length() > 0));

	}

	private void output(String text, boolean out) {

		if (out) {
			System.out.println(text);
		}
	}

	final String[] indent = { "", ".", "..", "...", "....", ".....", "......" };

	void printNode(Node node, int depth, boolean out) {

		String name = node.getNodeName();
		String value = node.getNodeValue();

		if (validStr(name) && !validStr(value)) {
			output(indent[depth] + name, out);
		} else if (!validStr(name) && validStr(value)) {
			output("V: " + value, out);
		} else {
			if (value.matches("\\S+")) {
				output(indent[depth] + value, out);
			}
		}

	}

	private String checkPrefix(Node node) {

		NodeList nodeList = node.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node subNode = nodeList.item(i);
			if (subNode.getNodeType() == Node.ELEMENT_NODE) {
				String name = subNode.getNodeName();
				int index = name.indexOf('_');
				return (index > 0) ? name.substring(0, index +1) : "";
			}
		}
		return "";
	}

	private void checkNode(Document doc, Node node, String objName) {

		NodeList nodeList = node.getChildNodes();
		for (int i = 0; i < nodeList.getLength(); i++) {
			Node subNode = nodeList.item(i);

			switch (node.getNodeType()) {
			case Node.ELEMENT_NODE:
				String name = subNode.getNodeName();
				if (name.equals("element")) {
					String newPrefix = checkPrefix(subNode);
					//output(indent[depth] + newPrefix + name, true);
					doc.renameNode(subNode, "", newPrefix + name);
					subNode = nodeList.item(i);
				} else if (name.equals("qmaster_response")) {
					doc.renameNode(subNode, "", objName);
					subNode = nodeList.item(i);
				} else {
					//printNode(subNode, depth, out);
				}
				checkNode(doc, subNode, objName);
				break;
			default:
				break;
			}
		}

	}

	public static void main(String[] args) {

		try {
			init();
			SGEXMLTest filter = new SGEXMLTest();
			filter.run();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}
